package com.jacky.iot;

import org.eclipse.californium.core.*;
import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.network.Endpoint;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.config.UdpConfig;
import org.eclipse.californium.elements.exception.ConnectorException;
import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider;
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.security.cert.Certificate;
import java.util.concurrent.TimeUnit;

public class ClientStartUp {

    private static final File CONFIG_FILE = new File("Californium3.properties");
    private static final String CONFIG_HEADER = "Californium CoAP Properties file for client";
    private static final int DEFAULT_MAX_RESOURCE_SIZE = 2 * 1024 * 1024; // 2 MB
    private static final int DEFAULT_BLOCK_SIZE = 512;

    static {
        CoapConfig.register();
        UdpConfig.register();
    }

    private static Configuration.DefinitionsProvider DEFAULTS = new Configuration.DefinitionsProvider() {

        @Override
        public void applyDefinitions(Configuration config) {
            config.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, DEFAULT_MAX_RESOURCE_SIZE);
            config.set(CoapConfig.MAX_MESSAGE_SIZE, DEFAULT_BLOCK_SIZE);
            config.set(CoapConfig.PREFERRED_BLOCK_SIZE, DEFAULT_BLOCK_SIZE);
        }
    };

    public static void main(String[] args) throws Exception {
        Configuration config = Configuration.createWithFile(CONFIG_FILE, CONFIG_HEADER, DEFAULTS);
        Configuration.setStandard(config);

          // 发送一个需要服务端确认的get请求
//        URI url = new URI("coap://127.0.0.1:5684/observable/t45a5ef?deviceId=dev159");
//        CoapClient client = new CoapClient(url);
//        Request request = Request.newGet();
//        request.setType(CoAP.Type.CON); // 表明此请求需要服务器确认
//        request.setConfirmable(true); // 与setType(CoAP.Type.CON)等效
//        client.setTimeout(10_000L);
//        client.advanced(new CoapHandler() {
//            @Override
//            public void onLoad(CoapResponse response) {
//
//            }
//
//            @Override
//            public void onError() {
//
//            }
//        }, request);

//        System.out.println("options: \n" + resp.getOptions());
//        System.out.println("pretty response: \n" + Utils.prettyPrint(resp));

        CoapClient client = new CoapClient("coaps://127.0.0.1:5684/obs");
//        CoapClient client = new CoapClient("coap://127.0.0.1:5684/obs");
//        CoapClient client = new CoapClient("coap://127.0.0.1:5683/obs?deviceId=dev123");
//        CoapClient client = new CoapClient("coaps://127.0.0.1:5684/hello");
        client.setEndpoint(getDtlsEndpoint());
//        CoapResponse coapResponse = client.get();
//        System.out.println(coapResponse.getResponseText());
//        URI url = new URI("coap://127.0.0.1:5684/observable");
//        CoapClient client = new CoapClient();
//        Request request = Request.newGet().setURI(url).setObserve();
//        request.setObserve();
//        request.setType(CoAP.Type.CON);
        CoapObserveRelation relation = client.observe(new CoapHandler() {
            @Override
            public void onLoad(CoapResponse response) {
                System.out.println("observer got resp:" + response.getResponseText());
            }

            @Override
            public void onError() {
                System.out.println("observer got error :");
            }
        });

        try {
            TimeUnit.SECONDS.sleep(60);
        } catch (InterruptedException e) {
        }
        System.out.println("---------------\nCancel Observe");
        relation.reactiveCancel();


        TimeUnit.SECONDS.sleep(60);

    }

    static Endpoint getDtlsEndpoint() throws GeneralSecurityException, IOException {
        SslContextUtil.Credentials clientCredentials = SslContextUtil.loadCredentials(
                SslContextUtil.CLASSPATH_SCHEME + "keystore.jks", "client", "keyPass".toCharArray(),
                "clientPass".toCharArray());
        Certificate[] trustedCertificates = SslContextUtil.loadTrustedCertificates(
                SslContextUtil.CLASSPATH_SCHEME + "trustStore.jks", "rootca", "trustPass".toCharArray());

        Configuration configuration = Configuration.createWithFile(Configuration.DEFAULT_FILE, "DTLS example client", DEFAULTS);

        DtlsConnectorConfig.Builder builder = DtlsConnectorConfig.builder(configuration);
//        builder.setPskStore(new SinglePskStore("Client_identity", "secretPSK".getBytes()));
        builder.setCertificateIdentityProvider(new SingleCertificateProvider(clientCredentials.getPrivateKey(), clientCredentials.getCertificateChain(),
                CertificateType.RAW_PUBLIC_KEY, CertificateType.X_509));
        builder.setCertificateIdentityProvider(new SingleCertificateProvider(
                clientCredentials.getPrivateKey(), clientCredentials.getCertificateChain(), CertificateType.RAW_PUBLIC_KEY,
                CertificateType.X_509
        )).setAdvancedCertificateVerifier(StaticNewAdvancedCertificateVerifier.builder()
                .setTrustedCertificates(trustedCertificates).setTrustAllRPKs().build());
        DTLSConnector dtlsConnector = new DTLSConnector(builder.build());
        CoapEndpoint endpoint = new CoapEndpoint.Builder().setConnector(dtlsConnector).build();
        endpoint.start();
        return endpoint;
    }
}